#pragma once

#define WFSPAN_LRULIST
#include <metalc/mlayer/_mlayer.h>
#include <dbg.h>
#include <metalc/block/mslab.h>
#include <metalc/block/mblock.h>
#include <dinfra/mpwf/spmc_list.h>

OU2INFUN(cls, wfspan_clspol)

/* 外部维护的最大线程数 */
extern cid_t __max_threads;

/* 优先从自己的队列满足， FIXME:应用队列b4stealing后不应该启用这个 */
/* 因为队列贴出请求时，自身队列一定为空 */
// #define LOCAL_FIRST

/* 优先blocked插入 */
// #define WFSPAN_BLOCKED_INSERT_TO_SPMC
/* 管理大内存块 */
#define WFSPAN_PREFETCH(...)	PREFETCH(__VA_ARGS__)


#define WFSPAN_PRINT(...)	INFO(__VA_ARGS__)
// #define WFSPAN_PRINT(...)	dbg_printf(__VA_ARGS__)


/* 数组形式，方便并行 */
// #define WFSPAN_MAX_THREAD	512
// #define WFSPAN_MAX_CLS		72
// static spmchead_t spmc_heads[WFSPAN_MAX_CLS][WFSPAN_MAX_THREAD];
// static deqreq_t deqreqs[WFSPAN_MAX_THREAD][WFSPAN_MAX_CLS];







typedef const struct wfspan_conf {
	const size_t mslab_size;
	const word_t slab_limits;

	// const size_t travel_p;
	const size_t travel_frac;
	
	const hword_t max_help_quota;

	const size_t max_sz;

	const size_t l1_minsz;
	const size_t l1_maxsz;

	
	const size_t l2_minsz;
	const size_t l2_maxsz;
	
	const szcls_t l1_clsnr;	
	const szcls_t l2_clsnr;
	const mblock_conf_t mblock_conf;
} wfspan_conf_t;

typedef hword_t (cls2maxnr)(szcls_t cls);

/* TODO: 减少帮助z过程中的Cache miss, 包括尽可能不修改帮助记录体(只读不修改) */

/* TODO: SPCMNODE最后一个节点可作为本地节点的保留节点(在真正移除前，还能在本地使用？) */

typedef struct wfspan_cls {
	/* TODO: dlist可以换成指针指向空节点 */
	dlist_t local_list;


	spmcnode_t *rflist_tail;

	/* 需要phase吗? 其实不需要吧，只要pengding亮了就帮也没有问题啊？ */
	/* 消除? */
	word_t lastphase_consumsed;
	
	// spmchead_t *last_query;
	// deqreq_t *last_helped;
	struct wfspan_obj *last_query;
	struct wfspan_obj *last_helped;
} wfspan_cls_t;

typedef struct wfspan_obj {
	word_t slab_nr;
	word_t full_nr;

	
	dlist_t full_local_list;

	dlist_t non_full_lru_list;	/* LRU链表，用于释放最近最久未使用非空节点 */
	
	dlist_t mblk_list;	/* 用于存放当前mblock指针 */

	word_t extra_space[]; 
	/* 以下必须通过动态实现 */
/* 	wfspan_cls_t szcls[MAX_SIZECLS]; // 本地经常修改
	struct
	{
		spmchead_t rflist_head[MAX_SIZECLS]; // 本地不修改，远程修改
	} CACHE_ALIGNED;
	struct
	{
		dreq_t szcls_rqs[MAX_SIZECLS]; 
		// 本地修改一次(发布)，也仅修改一次，为什么不改成一个?一个线程会同时发布多个szcls请求吗?并不会
		// 多一个节点可以插回去，节省空间
	} CACHE_ALIGNED;
	不变区，用于存放一些基本不变的信息
	// 如果spmchead和dreq_t放一块会怎么样?会不会降低cache miss
	// wfszcls也可以和dreq放一块?可以倒过来编址，大小-大小，这样省空间和cache行?试试看、
	spmcnode_t sentry;
	struct wfspan_obj *next */
} wfspan_obj_t;
 
SAI wfspan_cls_t *wfspanobj_get_clsarr(wfspan_obj_t *l){
	return (wfspan_cls_t *)((paddr_t)l + sizeof(wfspan_obj_t));
}
SAI spmchead_t *wfspanobj_get_spmclists(wfspan_obj_t *l, const szcls_t l1_clsnr, const size_t l2_clsnr){
	return (spmchead_t *)(align_up((paddr_t)wfspanobj_get_clsarr(l) + sizeof(wfspan_cls_t) * (l1_clsnr + l2_clsnr), HDEF_CACHE_LINE_BYTES));
}
/* TODO: 应该不用对齐? */
SAI deqreq_t *wfspanobj_get_deqreq(wfspan_obj_t *l, const szcls_t l1_clsnr, const size_t l2_clsnr){
	return (deqreq_t *)align_up((paddr_t)wfspanobj_get_spmclists(l, l1_clsnr, l2_clsnr) + sizeof(spmchead_t) * (l1_clsnr + l2_clsnr), HDEF_CACHE_LINE_BYTES);
}
/* TODO: 应该不用对齐? */
SAI spmcnode_t *wfspanobj_get_sentry(wfspan_obj_t *l, const szcls_t l1_clsnr, const size_t l2_clsnr){
	return (spmcnode_t *)align_up((paddr_t)wfspanobj_get_deqreq(l, l1_clsnr, l2_clsnr) + sizeof(deqreq_t) * (l1_clsnr + l2_clsnr), HDEF_CACHE_LINE_BYTES);
}
/* 下一个节点 */
SAI wfspan_obj_t **wfspanobj_get_nextp(wfspan_obj_t *l, const szcls_t l1_clsnr, const size_t l2_clsnr){
	return (wfspan_obj_t **)((paddr_t)wfspanobj_get_sentry(l, l1_clsnr, l2_clsnr) + sizeof(spmcnode_t));
}
SAI size_t wfspanobj_size(const szcls_t l1_clsnr, const size_t l2_clsnr){
	/* 取最后的next指针然后对齐cache行 */
	return align_up((paddr_t)wfspanobj_get_nextp((wfspan_obj_t *)NULL_PTR, l1_clsnr, l2_clsnr) + sizeof(wfspan_obj_t *), HDEF_CACHE_LINE_BYTES);
}
SAI void wfspan_remove_local_list(wfspan_obj_t *l, mslab_t *s){
	/* 需要释放span */
	dlist_del(s->node.prev, s->node.next);
	/* TODO: LRU节点移除 */
	dlist_del(s->tnode.prev, s->tnode.next);
	l->slab_nr -= 1;
}
SAI mslab_t *wfspan_pop_recently_unused(wfspan_obj_t *l){
	ASSERT(!list_is_empty(&l->non_full_lru_list));
	dlist_t *tail = l->non_full_lru_list.prev;
	/* TODO: 移除LRU节点 */
	ASSERT(tail->next == &l->non_full_lru_list);
	dlist_del(tail->prev, &l->non_full_lru_list);
	/* 移除free节点 */
	mslab_t *ret = list_entry(mslab_t, tail, tnode);
	dlist_del(ret->node.prev, ret->node.next);

	l->slab_nr -= 1;
	return ret;

}
SAI void wfspan_push_local_list_tail(wfspan_obj_t *l, wfspan_cls_t *szcls_arr, mslab_t *s, szcls_t cls){
	__dlist_insert(szcls_arr[cls].local_list.prev, &s->node, &s->node, &szcls_arr[cls].local_list);
	/* TODO: LRU节点插入 */
	__dlist_insert(&l->non_full_lru_list, &s->tnode, &s->tnode, l->non_full_lru_list.next);
	l->slab_nr += 1;

	// dlist_t *head = l->non_full_lru_list.next;
	// dlist_t *tail = l->non_full_lru_list.prev;
	// tail->next = NULL_PTR;
	// size_t cnt = slist_len_noloop((slist_t *)head);
	// if (cnt != l->slab_nr - 2 * l->full_nr){
	// 	dbg_INFO("LRU list len %lu, slab nr %lu, full_nr %lu\n", cnt, l->slab_nr, l->full_nr);
	// }
	// ASSERT(cnt == l->slab_nr - 2 * l->full_nr);
	// tail->next = &l->non_full_lru_list;
}
SAI void wfspan_push_local_list_head(wfspan_obj_t *l, wfspan_cls_t *szcls_arr, mslab_t *s, szcls_t cls){
	__dlist_insert(&szcls_arr[cls].local_list, &s->node, &s->node, szcls_arr[cls].local_list.next);
	/* TODO: LRU节点插入 */
	__dlist_insert(&l->non_full_lru_list, &s->tnode, &s->tnode, l->non_full_lru_list.next);


	l->slab_nr += 1;
	
	/* 检查LRU */
	// dlist_t *head = l->non_full_lru_list.next;
	// dlist_t *tail = l->non_full_lru_list.prev;
	// tail->next = NULL_PTR;
	// size_t cnt = slist_len_noloop((slist_t *)head);
	// if (cnt != l->slab_nr - 2 * l->full_nr){
	// 	dbg_INFO("LRU list len %lu, slab nr %lu, full_nr %lu\n", cnt, l->slab_nr, l->full_nr);
	// }
	// ASSERT(cnt == l->slab_nr - 2 * l->full_nr);
	// tail->next = &l->non_full_lru_list;

}
SAI void wfspan_push_full_local_list(wfspan_obj_t *l, szcls_t cls, mslab_t *s){;
	PARAM_USED(cls);

	l->full_nr += 1;
	l->slab_nr += 1;
	l->slab_nr += 1; /* FIXME: 加2次 */
	__dlist_insert(&l->full_local_list, &s->node, &s->node, l->full_local_list.next);

	/* 加入cls的full list */
	// wfspan_cls_t *wfscls = wfspanobj_get_clsarr(l);
	// __dlist_insert(&wfscls[cls].cls_full_list, &s->tnode, &s->tnode, wfscls[cls].cls_full_list.next);
}

SAI mslab_t *wfspan_pop_full_local_list(wfspan_obj_t *l){;
	/* 使用头部 */
	ASSERT(l->full_nr >= 1);
	dlist_t *cur_node = l->full_local_list.next;
	l->full_nr -= 1;
	l->slab_nr -= 1;
	l->slab_nr -= 1; /* FIXME: 减2次 */
	dlist_del(&l->full_local_list, cur_node->next);


	return list_entry(mslab_t, cur_node, node);
}

SAI mslab_t *wfspan_pop_tail_full_local_list(wfspan_obj_t *l){;
	/* 使用头部 */
	ASSERT(l->full_nr >= 1);
	dlist_t *cur_node = l->full_local_list.prev;
	l->full_nr -= 1;
	l->slab_nr -= 1;
	l->slab_nr -= 1; /* FIXME: 减2次 */
	dlist_del(cur_node->prev, &l->full_local_list);
	return list_entry(mslab_t, cur_node, node);
}

SAI void wfspan_remove_full_local_list(wfspan_obj_t *l, mslab_t *s){
	dlist_del(s->node.prev, s->node.next);
	l->full_nr -= 1;
	l->slab_nr -= 1; /* 减2次 */
	l->slab_nr -= 1; /* 减2次 */
}
SAI size_t wfspan_clear_full_local_list(wfspan_obj_t *l, dlist_t **phead, dlist_t **ptail){
	/* 清空l->full_nr */
	ASSERT(l->full_nr != 0);
	size_t fnr = l->full_nr;
	l->slab_nr -= fnr;
	l->slab_nr -= fnr; /* FIXME: 减2个 */
	l->full_nr = 0;
	
	*phead = l->full_local_list.next;
	*ptail = l->full_local_list.prev;

	// /* 测试 */
	// ret->prev->next = NULL_PTR;
	// ASSERT(slist_len_noloop((slist_t *)ret) == fnr);
	dlist_init(&l->full_local_list); 
	return fnr;
}
SAI void __wfspan_researved_mslabn(wfspan_obj_t *l, szcls_t cls, mslab_t *m, mslab_t *m_tail){
	/* TODO: 先得获取到rflist_tail */
	// ASSERT(m->allocator == NULL);
	wfspan_cls_t *szcls_arr = wfspanobj_get_clsarr(l);
	__spmcnode_push_batch_single(&szcls_arr[cls].rflist_tail, (spmcnode_t *)&m->node, (spmcnode_t *)&m_tail->node);
}

SAI void wfspan_researved_mslabn(wfspan_obj_t *l, szcls_t cls, mslab_t *m, mslab_t *m_tail){
	/* TODO: 先得获取到rflist_tail */
	// ASSERT(m->allocator == NULL);
	ASSERT(m->allocator == NULL_PTR);
	ASSERT(m == m_tail);
	__wfspan_researved_mslabn(l, cls, m, m_tail);
}

SIN mslab_t *wfspan_lockfree_fastpath(wfspan_obj_t *l, szcls_t cls, const bool_t should_pop, wfspan_conf_t *conf){
	mslab_t *ret = NULL_PTR;
	wfspan_cls_t *szcls_arr = wfspanobj_get_clsarr(l);
	spmchead_t *spmc_lists = wfspanobj_get_spmclists(l, conf->l1_clsnr, conf->l2_clsnr);
	spmcnode_t *sentry = wfspanobj_get_sentry(l, conf->l1_clsnr, conf->l2_clsnr);
	spmcnode_t *tail = szcls_arr[cls].rflist_tail;
	// return NULL_PTR;
	if (LIKELY(tail != (spmcnode_t *)&spmc_lists[cls].head)){
		/* 不为空 */ 
		spmcnode_t *tail_prev = tail->prev;
		/* 尝试获取，分两种情况，一种是不只有最后一个节点，需要原子操作；另一种是只有最后一个节点，无需原子操作*/
		if (tail_prev != (spmcnode_t *)&spmc_lists[cls].head){
			/* 不是最后一个节点，需要用cas尝试，如果被别人获取且修改了直接返回失败 */
			if (!should_pop) return NULL_PTR;
			/* 出队的tail_prev的next不可能指向tail */
			/* 如果没有指向next说明prev已经出队 */
			spmcnode_t *cas_tail = tail;
			if ((tail_prev->next == tail) && (cas_acq_s(&tail_prev->next, &cas_tail, NULL_PTR))){
				spmcnode_t *cur_head = atm_ld(&spmc_lists[cls].head);
				if (tail != cur_head){ 
					/* 这才是获得成功tail，可能还存在内存泄漏 */
					/* 当cur_head是tail_prev时，修改next为空，但cur_head依然会推进到tail */
					if (tail_prev != cur_head){
						/* 此时才能消费 */
						ret = (mslab_t *)tail;
						szcls_arr[cls].rflist_tail = tail_prev;
						return ret;
					}
					else{
						/* tail_prev == cur_head */
						/* 此时线程可能读取到了next为tail导致接下来head会被修改为tail */
						/* 此时回退修改?(有可能造成错误) */
						/* 因此rflist_tail不能指向tail_prev */
						/* 交换head为sentry? -交换结果为tail_prev时，返回tail_prev，并设置sentry 交换结果为tail时, 设置tail*/
						/* 这里可以写成cas形式，但似乎swp更快? */
						cur_head = swp(&spmc_lists[cls].head, tail);
						if (cur_head == tail_prev){
							ret = (mslab_t *)tail_prev;
							szcls_arr[cls].rflist_tail = tail;
							return ret;
						}
						/* cur_head != tail_prev的情况，说明推进到最后一个节点 */
					}
				}
			}
		}
		/* case 0: 是最后一个节点(tail_prev == (spmcnode_t *)&spmc_lists[cls].head)*/
		/* case 1: 不是最后一个，且tail == cur_head的情况 */
		spmc_lists[cls].head = sentry;
		/* 在aarch64上确保head写入完成之后才能正常使用tail，否则插入队列的过程有可能造成其他线程读取的tail出问题 */
		atm_strel(&tail->next, NULL_PTR);
		ret = (mslab_t *)tail;
		szcls_arr[cls].rflist_tail = (spmcnode_t *)&spmc_lists[cls].head;
	

		// if (tail_prev == (spmcnode_t *)&spmc_lists[cls].head){
			
		// 	spmc_lists[cls].head = sentry;
		// 	/* 需要额外初始化头部 */
		// 	ret = (mslab_t *)tail;
		// 	/* 初始化 */
		// 	szcls_arr[cls].rflist_tail = (spmcnode_t *)&spmc_lists[cls].head;
		// }
		// else{
		// 	/* 不是最后一个节点，需要用cas尝试，但是如果被别人获取了呢？*/
		// 	if (cas_acq(&tail_prev->next, &tail, NULL_PTR)) {
		// 		/* 读当前的头 */
		// 		spmcnode_t *cur_head = atm_ld(&spmc_lists[cls].head);
		// 		if (tail != cur_head){ 
		// 			/* 这才是获得成功tail，可能还存在内存泄漏 */
		// 			/* 当cur_head是tail_prev时，修改next为空，但cur_head依然会推进到tail */
		// 			if (tail_prev != cur_head){
		// 				/* 此时才能消费 */
		// 				ret = (mslab_t *)tail;
		// 				szcls_arr[cls].rflist_tail = tail_prev;
		// 			}
		// 			else{
		// 				/* tail_prev == cur_head */
		// 				/* 此时线程可能读取到了next为tail导致接下来head会被修改为tail */
		// 				/* 此时回退修改?(有可能造成错误) */
		// 				/* 因此rflist_tail不能指向tail_prev */
		// 				/* 交换head为sentry? -交换结果为tail_prev时，返回tail_prev，并设置sentry 交换结果为tail时, 设置tail*/
		// 				cur_head = swp(&spmc_lists[cls].head, tail);
		// 				if (cur_head == tail_prev){
		// 					ret = (mslab_t *)tail_prev;
		// 					szcls_arr[cls].rflist_tail = tail;
		// 				}else{
		// 					spmc_lists[cls].head = sentry;
		// 					/* 交换结果为tail，等价于tail == cur_head的情况*/
		// 					ret = (mslab_t *)tail;
		// 					szcls_arr[cls].rflist_tail = (spmcnode_t *)&spmc_lists[cls].head;
		// 				}
		// 			}
		// 		} else{
					
		// 			spmc_lists[cls].head = sentry;
		// 			/* tail == cur_head的情况 */
		// 			/* 还是被推进到这里了, 消耗tail */
		// 			ret = (mslab_t *)tail;
		// 			szcls_arr[cls].rflist_tail = (spmcnode_t *)&spmc_lists[cls].head;
		// 		}
		// 	}
		// }
	}
	return ret;
}
/* 为了提升局部性，窃取帮助过程应当优先从被窃取线程的队列中满足 
 * 窃取帮助过程之后，也应当从自己开始
*/
/* 改成直接窃取两个 */
/* 仅在...时跳过自己 */
/* TODO: deqreq放在spmchead里? */
/* TODO: 改成数组形式，可以循环展开 */
SNI HOT mslab_t *wfspan_waitfree_acquire(wfspan_obj_t *l, szcls_t cls, const bool_t local_first, wfspan_conf_t *conf, cid_t cid, tid_t tid){
	mslab_t *ret = NULL_PTR;
	wfspan_obj_t *query;
	wfspan_obj_t *query_next;
	wfspan_obj_t *lnext;
	word_t tstate;
	bool_t is_null = FALSE;

	wfspan_obj_t *help, *help_next;
	deqreq_t *cur_helped;
	spmcnode_t *tmp_node = NULL_PTR;
	deqreq_t *my_req;
	word_t state;
	word_t set_state;
	hword_t help_quota;
	word_t my_phase;
	hword_t visited = 0;
	hword_t help_cnt = 0;
	// 使用exchange直接阻塞式访问
	
	/* TODO: 获得本线程 req */
	wfspan_cls_t *szclsp = wfspanobj_get_clsarr(l);
	wfspan_cls_t *this_cls = &szclsp[cls];
	deqreq_t *deqreqp = wfspanobj_get_deqreq(l, conf->l1_clsnr, conf->l2_clsnr);
	
	/* 数组形式 N * C 个spmchead, N * C个deqreq_t, N*C个*/


	PARAM_USED(local_first, cid, tid);
	
	my_req = &deqreqp[cls];


	state = atm_ld(&my_req->state_word);


	/* 减少对全局cache的修改 */
	/* 尝试从结果中读取 */
	if (!(this_cls->lastphase_consumsed & 0x1UL) && (state != (word_t)NULL_PTR))
	{
		/* state != 0且未消耗state */
		ret = (mslab_t *)state;
		/* WFSPAN_PREFETCH(ret); */
		this_cls->lastphase_consumsed |= 0x1UL;
		ASSERT(ret);
		INFO("[wfspan acquire] reclaimed last helped %p\n", ret);
		/* 这样就能减少cache通讯开销 */
		return ret;
	}
	
	help = this_cls->last_helped;
	// !访问栈起始位置
	query = this_cls->last_query;

	help_next = atm_ld(wfspanobj_get_nextp(help, conf->l1_clsnr, conf->l2_clsnr));
	query_next =  atm_ld(wfspanobj_get_nextp(query, conf->l1_clsnr, conf->l2_clsnr));

	/* 读取当前最大线程数 */
	cid_t cur_maxtid = __max_threads;

#ifdef USE_WFQUEUE_PROTOCOL
	help_quota = cur_maxtid;
#else
	help_quota = conf->max_help_quota;
#endif
	// 最多访问线程数
	cid_t visit_nr = cur_maxtid >> conf->travel_frac;
	if (conf->travel_frac != 0)
		visit_nr += 1;

	// 发布
#ifdef USE_WFQUEUE_PROTOCOL
	static word_t glb_phase[USE_WFQUEUE_PROTOCOL];
	my_phase = faa(&glb_phase[cls], 2) & (~0x1UL);
#else
	/* 最后一位清零 */
	my_phase = (this_cls->lastphase_consumsed + 2) & (~0x1UL);
#endif
	/* 标记为未消耗 */
	this_cls->lastphase_consumsed = my_phase;
	set_state = __spmcnode_publish_deq_phase(my_req, (spmchead_t *)NULL_PTR, my_phase);
	// ASSERT((paddr_t)my_req->node == (my_phase | 0x1UL));


	/* TODO: 每个帮助请求先从自己的spmc中取， 逻辑应该能更简化 */
	ASSERT(help_quota >= 1 && visit_nr >= 1);
	ASSERT(!ret);

	/* 提前发射读取指令 */
	while (visited < visit_nr)
	{
		
		ASSERT(!is_null);
		cur_helped = &(wfspanobj_get_deqreq(help, conf->l1_clsnr, conf->l2_clsnr)[cls]);
		tstate = atm_ld(&cur_helped->state_word);
		if (deqreq_is_still_pending(tstate, my_phase, deqreq_state_phase(tstate)))
		{

			INFO("[wfspan acquire] %p try help %p, req %p\n", l, help, cur_helped);
			/* &query->rflist_head[cls]*/
			spmchead_t *query_lists = wfspanobj_get_spmclists(query, conf->l1_clsnr, conf->l2_clsnr);
			ret = (mslab_t *)spmcnode_help_finish_pop(&query_lists[cls], \
				&is_null, cur_helped, my_req, (spmcnode_t *)ret, tstate, my_phase, FALSE);
			if (is_null)
			{
				
				/* 推进query指针 */
				query = query_next;
				query_next = atm_ld(wfspanobj_get_nextp(query, conf->l1_clsnr, conf->l2_clsnr));
				// if (cur_maxtid > 1) ASSERT(query != query_next);
				is_null = FALSE;
				visited++;
				// 重新尝试，而不是
				continue;
			}
		}


		// 已完成帮助或者帮助状态已清空
		help = help_next;
		
		if(++help_cnt >= help_quota) break;
		help_next = atm_ld(wfspanobj_get_nextp(help, conf->l1_clsnr, conf->l2_clsnr));
	}
	
	ASSERT(!is_null);
	// !帮助完成后,尝试完成自己的节点, 若为空,推进下一个节点并i++

	// 等待状态
	while ((visited < visit_nr) && (!ret))
	{
		// !在此过程中若ret 不等于0, 关闭退出
		// !在此过程中若操作已被关闭, 则尝试获得ret后退出
		state = atm_ld(&my_req->state_word);
		if (!deqreq_state_pending(state)) {
			// !ret !被其他完成, 直接返回
			ASSERT(!ret);
			ret = (mslab_t *)state;
			INFO("[wfspan acquire] request completed by others %p\n", ret);
			/* 预取 */
			/* WFSPAN_PREFETCH(ret); */
			/* 这里改成直接将consumed设置为1，减少cache通讯开销 */
			ASSERT((this_cls->lastphase_consumsed & 0x1UL) == 0);
			this_cls->lastphase_consumsed |= 0x1UL;
			// 记录tid
			ASSERT(ret);
			goto RET;
		}
		spmchead_t *query_lists = wfspanobj_get_spmclists(query, conf->l1_clsnr, conf->l2_clsnr);
		ret = (mslab_t *)spmcnode_help_finish_pop(&query_lists[cls], 
			&is_null, my_req, my_req, (spmcnode_t *)ret, state, my_phase, TRUE);
		if (is_null){
			query = query_next;
			// query_next = atm_ld(&query->next);
			query_next = atm_ld(wfspanobj_get_nextp(query, conf->l1_clsnr, conf->l2_clsnr));
			
			is_null = FALSE;
			visited++;
		}
	}
	/* 有ret 之后直接关闭请求 */

	// 放在此处

	// 没找到，记录当前点后离去
	// 尝试关闭请求
	if (!cas_s(&my_req->state_word, &set_state, (word_t)NULL_PTR)){
		/* 修改失败，当前必定有值 */
		ASSERT(!(set_state & 0x1UL));
		if (!ret){
			ret = (mslab_t *)set_state;
			this_cls->lastphase_consumsed |=  0x1UL;
			INFO("[wfspan acquire] request completed before closing get %p\n", ret);
		}else{
			/* 得到两个 */
		}
		ASSERT(ret);
	} else{
		INFO("[wfspan acquire] closed request %p, cur get %p, visited %u\n", my_req, ret, visited);
	}
RET:
	INFO("[wf acquire] %p, last helped %p, last query %p, visted nr %x\n", ret, help_next, query, visited);
	
	/* 记录当前help */
	this_cls->last_helped = help;
	this_cls->last_query = query;
	return ret;
}



// SIN HOT mslab_t *wfspan_waitfree_acquire(wfspan_obj_t *l, szcls_t cls, const bool_t local_first, wfspan_conf_t *conf, cid_t cid, tid_t tid){
// 	mslab_t *ret = NULL_PTR;
// 	wfspan_obj_t *query;
// 	wfspan_obj_t *query_next;
// 	wfspan_obj_t *lnext;
// 	word_t tstate;
// 	bool_t is_null = FALSE;

// 	wfspan_obj_t *help, *help_next;
// 	deqreq_t *cur_helped;
// 	spmcnode_t *tmp_node = NULL_PTR;
// 	deqreq_t *my_req;
// 	word_t state;
// 	word_t set_state;
// 	hword_t help_quota;
// 	word_t my_phase;
// 	hword_t visited = 0;
// 	hword_t help_cnt = 0;
// 	// 使用exchange直接阻塞式访问
	
// 	/* TODO: 获得本线程 req */
// 	wfspan_cls_t *szclsp = wfspanobj_get_clsarr(l);
// 	wfspan_cls_t *this_cls = &szclsp[cls];
// 	deqreq_t *deqreqp = wfspanobj_get_deqreq(l, conf->l1_clsnr, conf->l2_clsnr);
	
// 	PARAM_USED(local_first, cid, tid);
	
// 	my_req = &deqreqp[cls];


// 	state = atm_ld(&my_req->state_word);


// 	/* 减少对全局cache的修改 */
// 	/* 尝试从结果中读取 */
// 	if (!(this_cls->lastphase_consumsed & 0x1UL) && (state != (word_t)NULL_PTR))
// 	{
// 		/* state != 0且未消耗state */
// 		ret = (mslab_t *)state;
// 		/* WFSPAN_PREFETCH(ret); */
// 		this_cls->lastphase_consumsed |= 0x1UL;
// 		ASSERT(ret);
// 		INFO("[wfspan acquire] reclaimed last helped %p\n", ret);
// 		/* 这样就能减少cache通讯开销 */
// 		return ret;
// 	}
	
// 	help = this_cls->last_helped;
// 	// !访问栈起始位置
// 	query = this_cls->last_query;

// 	help_next = atm_ld(wfspanobj_get_nextp(help, conf->l1_clsnr, conf->l2_clsnr));
// 	query_next =  atm_ld(wfspanobj_get_nextp(query, conf->l1_clsnr, conf->l2_clsnr));

// 	// 发布
// #ifdef USE_WFQUEUE_PROTOCOL
// 	static word_t glb_phase[USE_WFQUEUE_PROTOCOL];
// 	my_phase = faa(&glb_phase[cls], 2) & (~0x1UL);
// #else
// 	/* 最后一位清零 */
// 	my_phase = (this_cls->lastphase_consumsed + 2) & (~0x1UL);
// #endif
// 	/* 标记为未消耗 */
// 	this_cls->lastphase_consumsed = my_phase;
// 	set_state = __spmcnode_publish_deq_phase(my_req, (spmchead_t *)NULL_PTR, my_phase);
// 	// ASSERT((paddr_t)my_req->node == (my_phase | 0x1UL));
// 	/* 读取当前最大线程数 */
// 	cid_t cur_maxtid = __max_threads;

// #ifdef USE_WFQUEUE_PROTOCOL
// 	help_quota = cur_maxtid;
// #else
// 	help_quota = conf->max_help_quota;
// #endif
// 	// 最多访问线程数
// 	cid_t visit_nr = cur_maxtid >> conf->travel_frac;
// 	if (conf->travel_frac != 0)
// 		visit_nr += 1;

// 	/* TODO: 每个帮助请求先从自己的spmc中取， 逻辑应该能更简化 */
// 	ASSERT(help_quota >= 1 && visit_nr >= 1);
// 	ASSERT(!ret);

// 	/* 提前发射读取指令 */
// 	while (visited < visit_nr)
// 	{
// 		ASSERT(!is_null);
// 		cur_helped = &(wfspanobj_get_deqreq(help, conf->l1_clsnr, conf->l2_clsnr)[cls]);
// 		tstate = atm_ld(&cur_helped->state_word);
// 		if (deqreq_is_still_pending(tstate, my_phase, deqreq_state_phase(tstate)))
// 		{

// 			INFO("[wfspan acquire] %p try help %p, req %p\n", l, help, cur_helped);
// 			/* &query->rflist_head[cls]*/
// 			spmchead_t *query_lists = wfspanobj_get_spmclists(query, conf->l1_clsnr, conf->l2_clsnr);
// 			ret = (mslab_t *)__spmcnode_help_pop(&query_lists[cls], \
// 				&is_null, cur_helped, my_req, (spmcnode_t *)ret, tstate, my_phase, FALSE);
// 			if (is_null)
// 			{
				
// 				/* 推进query指针 */
// 				query = query_next;
// 				query_next = atm_ld(wfspanobj_get_nextp(query, conf->l1_clsnr, conf->l2_clsnr));
// 				// if (cur_maxtid > 1) ASSERT(query != query_next);
// 				is_null = FALSE;
// 				visited++;
// 				// 重新尝试，而不是
// 				continue;
// 			}
// 		}


// 		// 已完成帮助或者帮助状态已清空
// 		help = help_next;

// 		if (conf->max_help_quota > 1){
// 			help_next = atm_ld(wfspanobj_get_nextp(help, conf->l1_clsnr, conf->l2_clsnr));
// 		}

// 		if(++help_cnt >= help_quota) break;
// 	}
	
// 	ASSERT(!is_null);
// 	// !帮助完成后,尝试完成自己的节点, 若为空,推进下一个节点并i++

// 	// 等待状态
// 	while ((!ret) && (visited < visit_nr))
// 	{
// 		// !在此过程中若ret 不等于0, 关闭退出
// 		// !在此过程中若操作已被关闭, 则尝试获得ret后退出
// 		state = atm_ld(&my_req->state_word);
// 		if (!deqreq_state_pending(state)) {
// 			// !ret !被其他完成, 直接返回
// 			ASSERT(!ret);
// 			ret = (mslab_t *)state;
// 			INFO("[wfspan acquire] request completed by others %p\n", ret);
// 			/* 预取 */
// 			/* WFSPAN_PREFETCH(ret); */
// 			/* 这里改成直接将consumed设置为1，减少cache通讯开销 */
// 			ASSERT((this_cls->lastphase_consumsed & 0x1UL) == 0);
// 			this_cls->lastphase_consumsed |= 0x1UL;
// 			// 记录tid
// 			ASSERT(ret);
// 			goto RET;
// 		}
// 		spmchead_t *query_lists = wfspanobj_get_spmclists(query, conf->l1_clsnr, conf->l2_clsnr);
// 		ret = (mslab_t *)__spmcnode_help_pop(&query_lists[cls], 
// 			&is_null, my_req, my_req, (spmcnode_t *)ret, state, my_phase, TRUE);
// 		if (is_null){
// 			query = query_next;
// 			// query_next = atm_ld(&query->next);
// 			query_next = atm_ld(wfspanobj_get_nextp(query, conf->l1_clsnr, conf->l2_clsnr));
			
// 			is_null = FALSE;
// 			visited++;
// 		}
// 	}
// 	/* 有ret 之后直接关闭请求 */

// 	// 放在此处

// 	// 没找到，记录当前点后离去
// 	// 尝试关闭请求
// 	if (!cas_s(&my_req->state_word, &set_state, (word_t)NULL_PTR)){
// 		/* 修改失败，当前必定有值 */
// 		ASSERT(!(set_state & 0x1UL));
// 		if (!ret){
// 			ret = (mslab_t *)set_state;
// 			this_cls->lastphase_consumsed |=  0x1UL;
// 			INFO("[wfspan acquire] request completed before closing get %p\n", ret);
// 		}else{
// 			/* 得到两个 */
// 		}
// 		ASSERT(ret);
// 	} else{
// 		INFO("[wfspan acquire] closed request %p, cur get %p, visited %u\n", my_req, ret, visited);
// 	}
// RET:
// 	INFO("[wf acquire] %p, last helped %p, last query %p, visted nr %x\n", ret, help_next, query, visited);
	
// 	/* 记录当前help */
// 	this_cls->last_helped = help;
// 	this_cls->last_query = query;
// 	return ret;
// }


// SIN HOT mslab_t *wfspan_waitfree_acquire(wfspan_obj_t *l, szcls_t cls, const bool_t local_first, wfspan_conf_t *conf){
// 	mslab_t *ret = NULL_PTR;
// 	wfspan_obj_t *query;
// 	wfspan_obj_t *query_next;
// 	wfspan_obj_t *lnext;
// 	word_t tstate;
// 	bool_t is_null = FALSE;

// 	wfspan_obj_t *help, *help_next;
// 	deqreq_t *cur_helped;
// 	spmcnode_t *tmp_node = NULL_PTR;
// 	deqreq_t *my_req;
// 	word_t state;
// 	word_t set_state;
// 	hword_t help_quota;
// 	word_t my_phase;
// 	hword_t visited = 0;
// 	hword_t help_cnt = 0;
// 	// 使用exchange直接阻塞式访问
	
// 	/* TODO: 获得本线程 req */
// 	wfspan_cls_t *szclsp = wfspanobj_get_clsarr(l);
// 	wfspan_cls_t *this_cls = &szclsp[cls];
// 	deqreq_t *deqreqp = wfspanobj_get_deqreq(l, conf->l1_clsnr, conf->l2_clsnr);
	
// 	PARAM_USED(local_first);
	
// 	my_req = &deqreqp[cls];


// 	state = atm_ld(&my_req->state_word);


// 	/* 减少对全局cache的修改 */
// 	/* 尝试从结果中读取 */
// 	if (!(this_cls->lastphase_consumsed & 0x1UL) && (state != (word_t)NULL_PTR))
// 	{
// 		/* state != 0且未消耗state */
// 		ret = (mslab_t *)state;
// 		/* WFSPAN_PREFETCH(ret); */
// 		this_cls->lastphase_consumsed |= 0x1UL;
// 		ASSERT(ret);
// 		INFO("[wfspan acquire] reclaimed last helped %p\n", ret);
// 		/* 这样就能减少cache通讯开销 */
// 		return ret;
// 	}
	
// 	help = this_cls->last_helped;
// 	// !访问栈起始位置
// 	query = this_cls->last_query;
// 	query_next = atm_ld(wfspanobj_get_nextp(query, conf->l1_clsnr, conf->l2_clsnr));
// 	/* 会不会导致集中消费? */

// 	/* TODO: 试试从自己身边开始访问 */
// 	help_next = atm_ld(wfspanobj_get_nextp(help, conf->l1_clsnr, conf->l2_clsnr));


// 	// 发布
// #ifdef USE_WFQUEUE_PROTOCOL
// 	static word_t glb_phase[USE_WFQUEUE_PROTOCOL];
// 	my_phase = faa(&glb_phase[cls], 2) & (~0x1UL);
// #else
// 	/* 最后一位清零 */
// 	my_phase = (this_cls->lastphase_consumsed + 2) & (~0x1UL);
// #endif
// 	/* 标记为未消耗 */
// 	this_cls->lastphase_consumsed = my_phase;
// 	set_state = __spmcnode_publish_deq_phase(my_req, (spmchead_t *)NULL_PTR, my_phase);
// 	// ASSERT((paddr_t)my_req->node == (my_phase | 0x1UL));
// 	/* 读取当前最大线程数 */
// 	cid_t cur_maxtid = __max_threads;

// #ifdef USE_WFQUEUE_PROTOCOL
// 	help_quota = cur_maxtid;
// #else
// 	help_quota = conf->max_help_quota;
// #endif
// 	// 最多访问线程数
// 	cid_t visit_nr = cur_maxtid >> conf->travel_frac;
// 	if (conf->travel_frac != 0)
// 		visit_nr += 1;

// 	/* TODO: 每个帮助请求先从自己的spmc中取， 逻辑应该能更简化 */
// 	ASSERT(help_quota >= 1 && visit_nr >= 1);
// 	ASSERT(!ret);

// 	while ((help_cnt < help_quota) && (visited < visit_nr))
// 	{
// 		ASSERT(!is_null);
// 		cur_helped = &(wfspanobj_get_deqreq(help, conf->l1_clsnr, conf->l2_clsnr)[cls]);
// 		tstate = atm_ld(&cur_helped->state_word);
// 		if (deqreq_is_still_pending(tstate, my_phase, deqreq_state_phase(tstate)))
// 		{

// 			INFO("[wfspan acquire] %p try help %p, req %p\n", l, help, cur_helped);
// 			/* &query->rflist_head[cls]*/
// 			spmchead_t *query_lists = wfspanobj_get_spmclists(query, conf->l1_clsnr, conf->l2_clsnr);
// 			ret = (mslab_t *)__spmcnode_help_pop(&query_lists[cls], \
// 				&is_null, cur_helped, my_req, (spmcnode_t *)ret, tstate, my_phase, FALSE);
// 			if (is_null)
// 			{
				
// 				/* 推进query指针 */
// 				query = query_next;
// 				query_next = atm_ld(wfspanobj_get_nextp(query, conf->l1_clsnr, conf->l2_clsnr));
				
// 				// if (cur_maxtid > 1) ASSERT(query != query_next);
// 				is_null = FALSE;
// 				visited++;
// 				// 重新尝试，而不是
// 				continue;
// 			}
// 		}


// 		// 已完成帮助或者帮助状态已清空
// 		help = help_next;

// 		help_next = atm_ld(wfspanobj_get_nextp(help, conf->l1_clsnr, conf->l2_clsnr));
// 		if (cur_maxtid > 1) ASSERT(help != help_next);

// 		help_cnt++;
// 	}

// 	// !帮助完成后,尝试完成自己的节点, 若为空,推进下一个节点并i++

// 	// 等待状态
// 	while ((visited < visit_nr) && (!ret))
// 	{
// 		ASSERT(!is_null);
// 		// !在此过程中若ret 不等于0, 关闭退出
// 		// !在此过程中若操作已被关闭, 则尝试获得ret后退出
// 		state = atm_ld(&my_req->state_word);
// 		if (!deqreq_state_pending(state)) {
// 			// !ret !被其他完成, 直接返回
// 			ASSERT(!ret);
// 			ret = (mslab_t *)state;
// 			INFO("[wfspan acquire] request completed by others %p\n", ret);
// 			/* 预取 */
// 			/* WFSPAN_PREFETCH(ret); */
// 			/* 这里改成直接将consumed设置为1，减少cache通讯开销 */
// 			ASSERT((this_cls->lastphase_consumsed & 0x1UL) == 0);
// 			this_cls->lastphase_consumsed |= 0x1UL;
// 			// 记录tid
// 			ASSERT(ret);
// 			goto RET;
// 		}
// 		spmchead_t *query_lists = wfspanobj_get_spmclists(query, conf->l1_clsnr, conf->l2_clsnr);
// 		ret = (mslab_t *)__spmcnode_help_pop(&query_lists[cls], 
// 			&is_null, my_req, my_req, (spmcnode_t *)ret, state, my_phase, TRUE);

// 		if (is_null){
// 			query = query_next;
// 			// query_next = atm_ld(&query->next);
// 			query_next = atm_ld(wfspanobj_get_nextp(query, conf->l1_clsnr, conf->l2_clsnr));
			
// 			is_null = FALSE;
// 			visited++;
// 		}
// 	}
// 	/* 有ret 之后直接关闭请求 */

// 	// 放在此处

// 	// 没找到，记录当前点后离去
// 	// 尝试关闭请求
// 	if (!cas_s(&my_req->state_word, &set_state, (word_t)NULL_PTR)){
// 		/* 修改失败，当前必定有值 */
// 		ASSERT(!(set_state & 0x1UL));
// 		if (!ret){
// 			ret = (mslab_t *)set_state;
// 			this_cls->lastphase_consumsed |=  0x1UL;
// 			INFO("[wfspan acquire] request completed before closing get %p\n", ret);
// 		}else{
// 			/* 得到两个 */
// 		}
// 		ASSERT(ret);
// 	} else{
// 		INFO("[wfspan acquire] closed request %p, cur get %p, visited %u\n", my_req, ret, visited);
// 	}
// RET:
// 	INFO("[wf acquire] %p, last helped %p, last query %p, visted nr %x\n", ret, help_next, query, visited);
	
// 	/* 记录当前help */
// 	this_cls->last_helped = help;
// 	this_cls->last_query = query;
// 	return ret;
// }

// SIN mslab_t *wfspan_waitfree_acquire(wfspan_obj_t *l, szcls_t cls, const bool_t local_first, wfspan_conf_t *conf){
// 	mslab_t *ret = NULL;
// 	wfspan_obj_t *query;
// 	wfspan_obj_t *query_next;
// 	wfspan_obj_t *lnext;
// 	word_t tstate;
// 	bool_t is_null = FALSE;

// 	wfspan_obj_t *help, *help_next;
// 	deqreq_t *cur_helped;
// 	spmcnode_t *tmp_node = NULL;
// 	deqreq_t *my_req;
// 	word_t state;
// 	word_t set_state;
// 	hword_t help_quota;
// 	word_t my_phase;
// 	hword_t visited = 0;
// 	hword_t help_cnt = 0;
// 	// 使用exchange直接阻塞式访问
	
// 	/* TODO: 获得本线程 req */
// 	wfspan_cls_t *szclsp = wfspanobj_get_clsarr(l);
// 	wfspan_cls_t *this_cls = &szclsp[cls];
// 	deqreq_t *deqreqp = wfspanobj_get_deqreq(l, conf->l1_clsnr, conf->l2_clsnr);
	
// 	my_req = &deqreqp[cls];


// 	state = atm_ld(&my_req->state_word);


// 	/* 减少对全局cache的修改 */
// 	/* 尝试从结果中读取 */
// 	if (!(this_cls->lastphase_consumsed & 0x1UL) && (state != NULL_PTR))
// 	{
// 		/* state != 0且未消耗state */
// 		ret = (mslab_t *)state;
// 		/* WFSPAN_PREFETCH(ret); */
// 		this_cls->lastphase_consumsed |= 0x1UL;
// 		ASSERT(ret);
// 		INFO("[wfspan acquire] reclaimed last helped %p\n", ret);

// 		/* 这样就能减少cache通讯开销 */
// 		return ret;
// 	}
	
// 	help = this_cls->last_helped;
// 	// !访问栈起始位置
// 	query = this_cls->last_query;
// 	/* 会不会导致集中消费? */

// 	/* TODO: 试试从自己身边开始访问 */

// 	// query_next = *swfspanobj_get_nextp(query, conf->l1_clsnr);

// 	help_next = atm_ld(wfspanobj_get_nextp(help, conf->l1_clsnr, conf->l2_clsnr));
	
// 	lnext = atm_ld(wfspanobj_get_nextp(l, conf->l1_clsnr, conf->l2_clsnr));


// 	/* 获得next节点 */
// 	// 将当前帮助节点压入备选栈顶
// 	// 优先使用本栈
// 	wfspan_obj_t *query_p;
// 	if (local_first){
// 		query_p = query;
// 		query_next = query;
// 		query = help;
// 	}
// 	else{
// 		query_next = atm_ld(wfspanobj_get_nextp(query, conf->l1_clsnr, conf->l2_clsnr));
// 	}

// 	// 发布
// #ifdef USE_WFQUEUE_PROTOCOL
// 	static word_t glb_phase[USE_WFQUEUE_PROTOCOL];
// 	my_phase = faa(&glb_phase[cls], 2) & (~0x1UL);
// #else
// 	/* 最后一位清零 */
// 	my_phase = (this_cls->lastphase_consumsed + 2) & (~0x1UL);
// #endif
// 	/* 标记为未消耗 */
// 	this_cls->lastphase_consumsed = my_phase;
// 	set_state = __spmcnode_publish_deq_phase(my_req, (spmchead_t *)NULL_PTR, my_phase);
// 	ASSERT((paddr_t)my_req->node == my_phase | 0x1UL);
// 	/* 读取当前最大线程数 */
// 	extern cid_t __max_threads;
// 	cid_t cur_maxtid = __max_threads;
	
// #ifdef USE_WFQUEUE_PROTOCOL
// 	help_quota = cur_maxtid;
// #else
// 	help_quota = conf->max_help_quota;
// 	// help_quota = 0;	/* 测试不帮助会怎么样 */
// #endif
// 	// 最多访问线程数
// 	cid_t visit_nr = cur_maxtid >> conf->travel_frac;
// 	if (conf->travel_frac != 0)
// 		visit_nr += 1;
// 	// INFO("visit nr %u\n", visit_nr);
// 	/* TODO: 每个帮助请求先从自己的spmc中取， 逻辑应该能更简化 */
// 	ASSERT(help_quota >= 1 && visit_nr >= 1);

// 	while ((help_cnt < help_quota) && (visited < visit_nr))
// 	{
// 		ASSERT(!is_null);
// 		cur_helped = &(wfspanobj_get_deqreq(help, conf->l1_clsnr, conf->l2_clsnr)[cls]);
// 		tstate = atm_ld(&cur_helped->state_word);
// 		if (deqreq_is_still_pending(tstate, my_phase, deqreq_state_phase(tstate)))
// 		{

// 			INFO("[wfspan acquire] %p try help %p, req %p\n", l, help, cur_helped);
// 			/* &query->rflist_head[cls]*/
// 			spmchead_t *query_lists = wfspanobj_get_spmclists(query, conf->l1_clsnr, conf->l2_clsnr);
// 			ret = (mslab_t *)__spmcnode_help_pop(&query_lists[cls], \
// 				&is_null, cur_helped, my_req, (spmcnode_t *)ret, tstate, my_phase, FALSE);
// 			if (is_null)
// 			{
// 				if (query_next == help){
// 					// 跳过遍历自己，因为自己的在一开始尝试过，肯定没有
// 					query_next = atm_ld(wfspanobj_get_nextp(query, conf->l1_clsnr, conf->l2_clsnr));
// 				}
// 				if (local_first){
// 					if (query_p == query){
// 						/* 刚好推进下一个 */
// 						query_p = query_next;
// 					}
// 				}
// 				query = query_next;
// 				query_next = atm_ld(wfspanobj_get_nextp(query, conf->l1_clsnr, conf->l2_clsnr));

// 				is_null = FALSE;
// 				visited++;
// 				// 重新尝试，而不是
// 				continue;
// 			}
// 		}


// 		// 已完成帮助或者帮助状态已清空
// 		help = help_next;

// 		if(local_first) {
// 			/* 帮助光标下移时，query光标优先指help */
// 			query_next = query_p;
// 			query = help;
// 		}

// 		help_next = atm_ld(wfspanobj_get_nextp(help, conf->l1_clsnr, conf->l2_clsnr));
// 		help_cnt++;
// 	}

// 	// !帮助完成后,尝试完成自己的节点, 若为空,推进下一个节点并i++
// 	if (local_first){
// 		// 帮助完成后,从自己开始
// 		query_next = query_p;
// 		query = l;
// 		ASSERT(is_null == FALSE);
// 		// is_null = FALSE;
// 	}

// 	/* 自己则尝试从tail开始窃取?这样cache更友好。怎么实现? */
// 	/* 取tail，获得tail->prev，tail一定不会被消耗。尝试用cas操作将下一个节点的next改为空，实现出队这样也不会有ABA问题 */

// 	// 等待状态
// 	while ((visited < visit_nr) && (!ret))
// 	{
// 		ASSERT(!is_null);
// 		// !在此过程中若ret 不等于0, 关闭退出
// 		// !在此过程中若操作已被关闭, 则尝试获得ret后退出
// 		state = atm_ld(&my_req->state_word);
// 		if (!deqreq_state_pending(state)) {
// 			// !ret !被其他完成, 直接返回
// 			ret = (mslab_t *)state;
// 			INFO("[wfspan acquire] request completed by others %p\n", ret);
// 			/* 预取 */
// 			/* WFSPAN_PREFETCH(ret); */
// 			/* 这里改成直接将consumed设置为1，减少cache通讯开销 */
// 			ASSERT((this_cls->lastphase_consumsed & 0x1UL) == 0);
// 			this_cls->lastphase_consumsed |= 0x1UL;
// 			// 记录tid
// 			ASSERT(ret);
// 			goto RET;
// 		}
// 		spmchead_t *query_lists = wfspanobj_get_spmclists(query, conf->l1_clsnr, conf->l2_clsnr);
// 		ret = (mslab_t *)__spmcnode_help_pop(&query_lists[cls], 
// 			&is_null, my_req, my_req, (spmcnode_t *)ret, state, my_phase, TRUE);

// 		if (is_null)
// 		{
// 			// !推进下一个节点并重试
// 			if(local_first) {
// 				/* 因为从自己开始，所以下个节点一定不是自己? */
				
// 				if (query_p == query){
// 					/* 刚好推进下一个 */
// 					query_p = query_next;
// 				}
// 				if (query_next == l)
// 				{
// 					if (query_p == query_next){
// 						/* 刚好推进下一个 */
// 						query_p = lnext;
// 					}
// 					query_next = lnext;
					
// 				}
				
				
// 			}
// 			query = query_next;
// 			// query_next = atm_ld(&query->next);
// 			query_next = atm_ld(wfspanobj_get_nextp(query, conf->l1_clsnr, conf->l2_clsnr));
// 			is_null = FALSE;
// 			visited++;
// 		}
// 	}
// 	/* 有ret 之后直接关闭请求 */

// 	// 放在此处

// 	// 没找到，记录当前点后离去
// 	// 尝试关闭请求
// 	if (!cas(&my_req->state_word, &set_state, (word_t)NULL_PTR)){
// 		/* 修改失败，当前必定有值 */
// 		ASSERT(!(set_state & 0x1UL));
// 		if (!ret){
// 			ret = (mslab_t *)set_state;
// 			this_cls->lastphase_consumsed |=  0x1UL;
// 			INFO("[wfspan acquire] request completed before closing get %p\n", ret);
// 		}
// 		ASSERT(ret);
// 	}else{
// 		INFO("[wfspan acquire] closed request %p, cur get %p, visited %u\n", my_req, ret, visited);
// 	}
// RET:
// 	INFO("[wf acquire] %p, last helped %p, last query %p, visted nr %x\n", ret, help_next, query, visited);
	
// 	this_cls->last_helped = help_next;
// 	this_cls->last_query = query;
// 	return ret;
// }

SIN wfspan_obj_t *wfspan_init(void *mem, size_t size, wfspan_conf_t *conf){
	/* 断言条件 */
	static wfspan_obj_t *glbvis_wfspans_head = (wfspan_obj_t *)NULL_PTR;
	static wfspan_obj_t *glbvis_wfspans = (wfspan_obj_t *)&glbvis_wfspans_head;

	size_t wfspan_sz = wfspanobj_size(conf->l1_clsnr, conf->l2_clsnr);
	ASSERT(mem && size >= wfspan_sz);

	wfspan_obj_t *ret = (wfspan_obj_t *)mem;
	/* 直接初始化 */
	// __memset(ret, 0, wfspan_sz);
	
	ret->slab_nr = 0;
	ret->full_nr = 0;

	dlist_init(&ret->full_local_list);
	dlist_init(&ret->non_full_lru_list);
	dlist_init(&ret->mblk_list);
	
	wfspan_cls_t *szclsp = wfspanobj_get_clsarr(ret);
	spmcnode_t *sentry = wfspanobj_get_sentry(ret, conf->l1_clsnr, conf->l2_clsnr);
	spmchead_t *spmclistp = wfspanobj_get_spmclists(ret, conf->l1_clsnr, conf->l2_clsnr);
	// deqreq_t *deqreqp = wfspanobj_get_deqreq(ret, conf->l1_clsnr, conf->l2_clsnr);
	wfspan_obj_t **pnext = wfspanobj_get_nextp(ret, conf->l1_clsnr, conf->l2_clsnr);
	sentry->next = NULL_PTR;
	sentry->prev = NULL_PTR;
	for (szcls_t cls = 0; cls < conf->l1_clsnr + conf->l2_clsnr; cls++){
		__spmcnode_head_init(&spmclistp[cls], sentry);
		// __spmcnode_head_init(&spmclistp[cls], &spmclistp[cls].sentry);
		/* 先指向自己 */
		// spmclistp[cls].next_head = &spmclistp[cls];
		// deqreqp[cls].next_req = &deqreqp[cls];

		/* 这样第一次写入会改变head */
		szclsp[cls].rflist_tail = (spmcnode_t *)&spmclistp[cls].head;
		szclsp[cls].last_query = ret;
		szclsp[cls].last_helped = ret;
		// szclsp[cls].last_query = &spmclistp[cls];
		// szclsp[cls].last_helped = &deqreqp[cls];

		/* 连接到null_node上 */
		// szclsp[cls].local_list = &ret->local_null_node;
		dlist_init(&szclsp[cls].local_list);
	}
	
	/* 加入全局链表 */
	wfspan_obj_t *cur_head = atm_ld(&glbvis_wfspans_head);
	wfspan_obj_t *cur_tail;

	/* 头部为空时修改为自己 */
	while (!cur_head)
	{
		/* rel才行 */
		if (cas_rel_s(&glbvis_wfspans_head, &cur_head, ret))
		{
			cur_head = ret;
			break;
		}
	}
	
	/* 连接next和头部 */
	atm_st(pnext, cur_head);
	
	// szclsp[cls].last_helped = cur_head;
	// szclsp[cls].last_query = cur_head;

	// spmchead_t *curhead_spmclist = wfspanobj_get_spmclists(cur_head, conf->l1_clsnr, conf->l2_clsnr);
	
	// // deqreq_t *curhead_deqreq = wfspanobj_get_deqreq(cur_head, conf->l1_clsnr, conf->l2_clsnr);
	for (szcls_t cls = 0; cls < conf->l1_clsnr + conf->l2_clsnr; cls++){
		/* 指向下一个的spmclist */
		// atm_st(&spmclistp[cls].next_head, &curhead_spmclist[cls]);
		// // atm_st(&deqreqp[cls].next_req, &curhead_deqreq[cls]);
		// szclsp[cls].last_helped = cur_head;
		// szclsp[cls].last_query = &curhead_spmclist[cls];

		szclsp[cls].last_helped = cur_head;
		szclsp[cls].last_query = cur_head;
	}
	/* 头部不为空时挂在队列尾部 */
	cur_tail = swp_rel(&glbvis_wfspans, ret);
	if (cur_tail != (wfspan_obj_t *)&glbvis_wfspans_head){
		/* 连接cur_tail的尾部 */
		atm_st(wfspanobj_get_nextp(cur_tail, conf->l1_clsnr, conf->l2_clsnr), ret);
		// spmchead_t *curtail_spmclist = wfspanobj_get_spmclists(cur_tail, conf->l1_clsnr, conf->l2_clsnr);
		// // deqreq_t *curtail_deqreq = wfspanobj_get_deqreq(cur_tail, conf->l1_clsnr, conf->l2_clsnr);
		// /* 连接spmc头 */
		// for (szcls_t cls = 0; cls < conf->l1_clsnr + conf->l2_clsnr; cls++){
		// 	/* 指向自己的spmclist */
		// 	atm_st(&curtail_spmclist[cls].next_head, &spmclistp[cls]);
		// 	// atm_st(&curtail_deqreq[cls].next_req, &deqreqp[cls]);
		// }
	}
	
	/* 检查是否是环 */
	

	/* 确保成环 */
	/* FIXME: 成环 */
	// word_t nr = 0;
	// wfspan_obj_t *c = cur_head;
	// do {
	// 	nr++;
	// 	c = atm_ld(wfspanobj_get_nextp(c, conf->l1_clsnr, conf->l2_clsnr));
	// } while(c != cur_head);
	// INFO("is a loop, nr %lu\n", nr);
	// ASSERT(nr >= 1);

	return ret;
}


/* 清理spmclists避免存在大量已申请的内存无法得到复用 */
/* 线程结束时碎片整理 */
/* 也可以在其他时候进行有限的碎片整理 */
/* TODO: 增加碎片整理的上限，例如只对前10个进行整理 */
/* 调用这个有可能造成最差情况内存占用无上界 */
SIN HOT size_t wfspan_clean_spmclists_limit(wfspan_obj_t *l, szcls_t cls, mslab_t *s, dlist_t **phead, dlist_t **ptail, size_t limit_nr, wfspan_conf_t *conf){
	wfspan_cls_t *szclsp = wfspanobj_get_clsarr(l);
	dlist_t ret_node;
	dlist_t rest_list;
	dlist_t *ret = NULL_PTR;
	size_t ret_nr = 0;
	size_t visit_nr = 0;
	
	spmcnode_t *sentry = wfspanobj_get_sentry(l, conf->l1_clsnr, conf->l2_clsnr);
	spmchead_t *spmclistp = wfspanobj_get_spmclists(l, conf->l1_clsnr, conf->l2_clsnr);
	spmcnode_t *snode = (spmcnode_t *)&s->node;	

	dlist_init(&ret_node);
	dlist_init(&rest_list);

	// spmcnode_t *sentry = &spmclistp[cls].sentry;
	ASSERT(snode->next == NULL_PTR);
	ASSERT(snode != sentry);
	ASSERT(sentry->next == NULL_PTR);
	/* 插入新队列 */
	spmcnode_t *old_tail = szclsp[cls].rflist_tail;
	if (snode != sentry){ 
		/* 不是sentry */
		szclsp[cls].rflist_tail = snode;
		/* 添加到snode后方 */
	}
	else{
		/* 是sentry */
		szclsp[cls].rflist_tail = (spmcnode_t *)(&spmclistp[cls].head);
		/* 修改头部 */
	}
	/* 先获取 */
	
	snode->prev = (spmcnode_t *)&spmclistp[cls].head;
	snode->next = NULL_PTR;
	s->allocator = NULL_PTR;

	/* 以下都需要快速完成 */
	spmcnode_t *cur_head = spmcnode_reclaim_all(&spmclistp[cls], snode);
	spmcnode_t *cur_tail;

	/* 搜索head到tail之间的full_list */
	spmcnode_t *cursor = cur_head;
	spmcnode_t *cursor_next;
	mslab_t *cur_slab;
	if (cursor != sentry){
		/* 仅当cursor存在时可以 */
		while (cursor) {
			/* 只要存在都可以 */
			cur_slab = (mslab_t *)cursor;
			cursor_next = cursor->next;
			if (mslab_is_full(cur_slab)){
				/* 可以释放，添加到队列中 */
				dlist_add_tail(&ret_node, (dlist_t *)cursor);
				ret_nr++;
			}
			else{
				/* 不是满的，添加到剩余队列中 */
				dlist_add_tail(&rest_list, (dlist_t *)cursor);
			}

			if(++visit_nr > limit_nr){
				/* 超过限制，将已访问的rest_list插入到cursor ... tail的尾部 */
				if(!cursor_next){
					/* 刚好到达 */
					break;
				}
				/* 使用cursor_next...old_tail - restlist.next - .. restlist.prev */
				ASSERT(old_tail != (spmcnode_t *)(&spmclistp[cls].head));
				/* 插到rest_list和rest_list.next之间 */
				__dlist_insert(&rest_list, (dlist_t *)cursor_next, (dlist_t *)old_tail, rest_list.next);
				break;
			}
			cursor = cursor_next;
		}
	}

	if (!list_is_empty(&rest_list)){
		/* 剩余未满的插回 */
		cur_head = (spmcnode_t *)rest_list.next;
		cur_tail = (spmcnode_t *)rest_list.prev;
		__spmcnode_push_batch_single(&szclsp[cls].rflist_tail, cur_head, cur_tail);
	}
	if (ret_nr != 0){
		*phead = ret_node.next;
		*ptail = ret_node.prev;
		INFO("[wfspan clean] from %p to %p, nr %lu\n", *phead, *ptail, ret_nr);
		if (!list_is_empty(&rest_list)){
			INFO("[wfspan clean] rest list %p - %p\n", rest_list.next, rest_list.prev);
		}
	}

	return ret_nr;
}

SIN size_t wfspan_clean_spmclists(wfspan_obj_t *l, szcls_t cls, mslab_t *s, dlist_t **phead, dlist_t **ptail, wfspan_conf_t *conf){
	wfspan_cls_t *szclsp = wfspanobj_get_clsarr(l);
	dlist_t ret_node;
	dlist_t rest_list;
	dlist_t *ret = NULL_PTR;
	size_t ret_nr = 0;
	size_t visit_nr;
	
	spmcnode_t *sentry = wfspanobj_get_sentry(l, conf->l1_clsnr, conf->l2_clsnr);
	spmchead_t *spmclistp = wfspanobj_get_spmclists(l, conf->l1_clsnr, conf->l2_clsnr);
	spmcnode_t *snode = (spmcnode_t *)&s->node;	

	dlist_init(&ret_node);
	dlist_init(&rest_list);

	// spmcnode_t *sentry = &spmclistp[cls].sentry;
	ASSERT(snode->next == NULL_PTR);
	ASSERT(snode != sentry);
	ASSERT(sentry->next == NULL_PTR);
	/* 插入新队列 */
	if (snode != sentry){ 
		/* 不是sentry */
		szclsp[cls].rflist_tail = snode;
		/* 添加到snode后方 */
	}
	else{
		/* 是sentry */
		szclsp[cls].rflist_tail = (spmcnode_t *)(&spmclistp[cls].head);
		/* 修改头部 */
	}
	/* 先获取 */
	
	snode->prev = (spmcnode_t *)&spmclistp[cls].head;
	snode->next = NULL_PTR;
	s->allocator = NULL_PTR;

	/* 以下都需要快速完成 */
	spmcnode_t *cur_head = spmcnode_reclaim_all(&spmclistp[cls], snode);
	spmcnode_t *cur_tail;

	/* 搜索head到tail之间的full_list */
	spmcnode_t *cursor = cur_head;
	spmcnode_t *cursor_next;
	mslab_t *cur_slab;
	if (cursor != sentry){
		/* 仅当cursor存在时可以 */
		// ASSERT(is_ptr_aligned(cursor, conf->mslab_size));
		while (cursor) {
			/* 只要存在都可以 */
			// ASSERT(is_ptr_aligned(cursor, conf->mslab_size));
			ASSERT(cursor != sentry);
			cursor_next = cursor->next;
			cur_slab = (mslab_t *)cursor;
			// ASSERT(is_ptr_aligned(cur_slab, conf->mslab_size));
			if (mslab_is_full(cur_slab)){
				/* 可以释放，添加到队列中 */
				dlist_add_tail(&ret_node, (dlist_t *)cursor);
				ret_nr++;
			}
			else{
				/* 不是满的，添加到剩余队列中 */
				dlist_add_tail(&rest_list, (dlist_t *)cursor);
			}
			
			cursor = cursor_next;
		}
	}
	/* 立即插回 */
	if (!list_is_empty(&rest_list)){
		/* 剩余未满的插回 */
		cur_head = (spmcnode_t *)rest_list.next;
		cur_tail = (spmcnode_t *)rest_list.prev;
		ASSERT((paddr_t)cur_tail->prev != (paddr_t)&spmclistp[cls].head);
		__spmcnode_push_batch_single(&szclsp[cls].rflist_tail, cur_head, cur_tail);
	}
	/* 尽可能快的完成搜索过程，不能阻塞队列过久 */
	/* 再去考虑自己的 */
	if (ret_nr != 0){
		// *pfhead = ret_node.next;
		ASSERT(!list_is_empty(&ret_node));
		*phead = ret_node.next;
		*ptail = ret_node.prev;
		INFO("[wfspan clean] from %p to %p, nr %lu\n", ret, ret->prev, ret_nr);
		if (!list_is_empty(&rest_list)){
			INFO("[wfspan clean] rest list %p - %p\n", rest_list.next, rest_list.prev);
		}
	}

	return ret_nr;
}

SAI bool_t wfslab_try_alloc(mslab_t *cur, void **ptmp, size_t slab_size, hword_t unit_size)
{
	/* 由于wfspan空的都被抛弃，尝试申请的一定只有阻塞和成功获得内存块两种结果 */
	void *tmp_ret = mslab_try_alloc(cur, slab_size, unit_size);
	if (tmp_ret == SLAB_FLIST_BLCOKED){
		return FALSE;
	}
	else{
		*ptmp = tmp_ret;
		return TRUE;
	}
}

SAI RETURN_NONULL void *wfslab_local_init_alloc(wfspan_obj_t *l, void *slab_ptr, const size_t slab_size, wfspan_cls_t *szcls_arr, szcls_t cls, hword_t unit_size, hword_t max_nr){
	void *ret;	
	ASSERT(is_ptr_aligned(slab_ptr, slab_size));
	/* 不使用Mblock */
#ifndef WFSPAN_MBLOCK
	void *bump_ptr;
	mslab_t *cur_slab = (mslab_t *)slab_ptr;
	wfspan_push_local_list_head(l, szcls_arr, cur_slab, cls);	
	

	/* 对齐用 */
	if (is_powerof2(unit_size)) bump_ptr = (void *)align_up((paddr_t)cur_slab + align_up(sizeof(mslab_t), HDEF_CACHE_LINE_BYTES), unit_size);
	else bump_ptr = (void *)((paddr_t)cur_slab + align_up(sizeof(mslab_t), HDEF_CACHE_LINE_BYTES));
	mslab_init(cur_slab, bump_ptr, l, slab_size, unit_size, max_nr, cls);

#else
	mslab_t *cur_slab = mslab_by_ptr_from_mblock(slab_ptr, WFSPAN_MBLOCK, slab_size);
	wfspan_push_local_list_head(l, szcls_arr, cur_slab, cls);
	mslab_init(cur_slab, slab_ptr, l, slab_size, unit_size, max_nr, cls);	
#endif

	// ASSERT(cur_slab->cls == cls);
	// ASSERT(cur_slab->flist == MSLAB_OFFST_NEXT);
#ifndef OLD_FLIST
	ret = mslab_try_alloc(cur_slab, slab_size, unit_size);
#else
	ret = mslab_init_alloc(cur_slab, unit_size);
#endif
	/* TODO: 只消耗一个也不会到达边界 */
	/* TODO: 不需要抛弃， 除非一个cur_slab数量等于1 */
	ASSERT(max_nr != 1);
	INFO("[wfspan] local alloc %p from full list, slab %p, slab_ptr %p\n", ret, cur_slab, slab_ptr);
	return ret;
}


/* 本地申请 */
SAI void *wfspan_local_alloc(wfspan_obj_t *l, wfspan_cls_t *szcls_arr, szcls_t cls, hword_t unit_size, wfspan_conf_t *conf){
	mslab_t *cur_slab;
	void *ret;
	if (!list_is_empty(&szcls_arr[cls].local_list)){
		/* 非空，从本地获得 */
		WFSPAN_PRINT("[wfspan] local alloc from cls %u\n", cls);
		dlist_t *cur_node = szcls_arr[cls].local_list.next;
		cur_slab = list_entry(mslab_t, cur_node, node);
		// ASSERT(next_node != NULL_PTR);
		dlist_t *prev_node = &szcls_arr[cls].local_list;
		

		ASSERT(cur_slab->cls == cls);
		if (wfslab_try_alloc(cur_slab, &ret, conf->mslab_size, unit_size)){
			/* 成功获得，先尝试discard */
			/* LRU节点 */
			WFSPAN_PRINT("[wfspan] local alloc succ %p in [%p]\n", ret, cur_slab);
			if (!cur_slab->flist)
			{
				/* 避免额外读取 */
				dlist_t *tprev_node = atm_ld(&cur_slab->tnode.prev);
				dlist_t *tnext_node = atm_ld(&cur_slab->tnode.next);
				dlist_t *next_node = atm_ld(&cur_node->next);
				if (mslab_discard(cur_slab, l)){
					// 出队
					WFSPAN_PRINT("[wfspan] local discarded %p\n", cur_slab);
					
					dlist_del(prev_node, next_node);
					dlist_del(tprev_node, tnext_node);
					l->slab_nr--;
				}
			}

			return ret;
		}
		else{
			/* 从本地获得失败(被阻塞) */
			WFSPAN_PRINT("[wfspan] local alloc blocked!!!! inseted %p to tail\n", cur_node);
			/* 删除后插到队列尾部 */
			dlist_del(prev_node, cur_node->next);
			/* TODO: LRU不变 */
			__dlist_insert(szcls_arr[cls].local_list.prev, cur_node, cur_node, &szcls_arr[cls].local_list);
		}
	}
	return NULL_PTR;
}

SAI void *wfspan_local_full_alloc(wfspan_obj_t *l, wfspan_cls_t *szcls_arr, szcls_t cls, hword_t unit_size, hword_t max_nr, wfspan_conf_t *conf){
	void *ret = NULL_PTR;
	// if (!list_is_empty(&l->full_local_list)){
	if (l->full_nr != 0){
		/* full_list非空 */
		mslab_t *cur_slab = wfspan_pop_full_local_list(l);
		// dbg_printf("[wfspan] local full list get slab %p\n", cur_slab);
#ifdef WFSPAN_MBLOCK
		void *slab_ptr = mslab_usable_in_mblock(cur_slab, WFSPAN_MBLOCK, conf->mslab_size);
		// if(cur_slab->cls == cls){
		// 	// dbg_printf("claimed a span %p\n", cur_slab);
		// 	bool_t succ = wfslab_try_alloc(cur_slab, &ret, conf->mslab_size, unit_size);
		// 	ASSERT(succ);
		// 	if(!cur_slab->flist){
		// 		/* 回收，没人使用所以直接就可以 */
		// 		cur_slab->flist = cur_slab->rlist.head;
		// 		cur_slab->rlist.head = NULL_PTR;
		// 		cur_slab->rlist.cnt_val += cur_slab->consumed_cnt;
		// 		cur_slab->consumed_cnt = 0;
		// 	}
			
		// 	/* 因为可能修改过，必须先改回来 */
		// 	cur_slab->unit_size = unit_size;
		// 	wfspan_push_local_list_head(l, szcls_arr, cur_slab, cls);
		// }else{
			ret = wfslab_local_init_alloc(l, slab_ptr, conf->mslab_size, szcls_arr, cls, unit_size, max_nr);
		// }
#else
		void *slab_ptr = cur_slab;
		/* 这个过程会保留slab局部性，提升分配的速度 */
		// if(cur_slab->cls == cls){
		// 	// dbg_printf("claimed a span %p\n", cur_slab);
		// 	wfslab_try_alloc(cur_slab, &ret, conf->mslab_size, unit_size);
		// 	ASSERT(succ);
		// 	if(!cur_slab->flist){
		// 		/* 回收，没人使用所以直接就可以 */
		// 		cur_slab->flist = cur_slab->rlist.head;
		// 		cur_slab->rlist.head = NULL_PTR;
		// 		cur_slab->rlist.cnt_val += cur_slab->consumed_cnt;
		// 		cur_slab->consumed_cnt = 0;
		// 	}
		// 	wfspan_push_local_list_head(l, szcls_arr, cur_slab, cls);
		// }else{
			ret = wfslab_local_init_alloc(l, slab_ptr, conf->mslab_size, szcls_arr, cls, unit_size, max_nr);
		// }
#endif

	}
	return ret;
}

SAI void *wfspan_acquire_from_others(wfspan_obj_t *l, mslab_t *cur_slab, wfspan_cls_t *szcls_arr, szcls_t cls, size_t unit_size, wfspan_conf_t *conf, cid_t cid, tid_t tid){
	WFSPAN_PRINT("[wfspan] try stealing cls spmc %u\n", cls);
	void *ret = NULL_PTR;

	/* 先尝试从spmc队列中取，取失败了尝试窃取 */
	if (!cur_slab) {
		if(__max_threads > 1)
			cur_slab = wfspan_waitfree_acquire(l, cls, 0, conf, cid, tid);
	}
	/* 直接local first窃取 */
	// cur_slab = wfspan_waitfree_acquire(l, cls, 1, conf);

	if (LIKELY(cur_slab)){
		WFSPAN_PRINT("[wfspan] steal %p from %u\n", cur_slab, cls);
		/* 窃取成功 */
		/* TODO: 该赋值似乎不需要 */
		/* 尝试在该span分配 */
		ASSERT(cur_slab->allocator == NULL);
		if (wfslab_try_alloc(cur_slab, &ret, conf->mslab_size, unit_size)){	
			/* 分配成功 */
			WFSPAN_PRINT("[wfspan] try alloc %p from stealed %p\n", ret, cur_slab);
			if (!mslab_discard_ifempty(cur_slab, l)){
				/* 不用抛弃 */
				WFSPAN_PRINT("[wfspan] insert stealed slab %p to local cls %u head\n", cur_slab, cls);
				/* 插入头部 */
				wfspan_push_local_list_head(l, szcls_arr, cur_slab, cls);
				ASSERT(cur_slab->cls == cls);
				cur_slab->allocator = l;
			}
		}
		else{
			WFSPAN_PRINT("[wfspan] insert stealed slab %p to spmc cls %u tail\n", cur_slab, cls);
			/* TODO: 塞回去还是插入到队列尾部 */
// #ifdef WFSPAN_BLOCKED_INSERT_TO_SPMC
// 			wfspan_researved_mslabn(l, cls, cur_slab, cur_slab);
// #else
// 			cur_slab->allocator = l;
// 			/* 插入头部或者尾部都可以，因为尾部和头部都为空 */
// 			__dlist_insert(szcls_arr[cls].local_list.prev, &cur_slab->node, &cur_slab->node, &szcls_arr[cls].local_list);
// 			ASSERT(cur_slab->cls == cls);
// 			l->slab_nr++;
// #endif
			// ASSERT(cur_slab->consumed_cnt == 0);
			wfspan_researved_mslabn(l, cls, cur_slab, cur_slab);
		}
	}
	return ret;
}